﻿using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using Acid.Math;
 
namespace Acid.Graphics
{  
    /// <summary>
    /// <para>Acid Default Mesh Class.</para>
    /// </summary>
    public class Mesh : IDisposable
    {
        #region Vertex Structure

        [StructLayout(LayoutKind.Sequential)]
        public struct Vertex
        {
            public Vertex(float px, float py, float pz) : this(px, py, pz, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f) { }
            public Vertex(float px, float py, float pz, float nx, float ny, float nz) : this(px, py, pz, nx, ny, nz, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f) { }
            public Vertex(float px, float py, float pz, float nx, float ny, float nz, float tx, float ty, float tz, float bx, float by, float bz) : this(px, py, pz, nx, ny, nz, tx, ty, tz, bx, by, bz, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f) { }
            public Vertex(float px, float py, float pz, float nx, float ny, float nz, float tcx, float tcy) : this(px, py, pz, nx, ny, nz, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, tcx, tcy) { }
            public Vertex(float px, float py, float pz, float tcx, float tcy) : this(px, py, pz, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, tcx, tcy) { }
            public Vertex(float px, float py, float pz,
                          float nx, float ny, float nz,
                          float tx, float ty, float tz,
                          float bx, float by, float bz,
                          float cx, float cy, float cz,
                          float tcx, float tcy)
            {
                this.position = new Vector3(px, py, pz);
                this.normal   = new Vector3(nx, ny, nz);
                this.tangent  = new Vector3(tx, ty, tz);
                this.binormal = new Vector3(bx, by, bz);
                this.color    = new Vector3(cx, cy, cz);
                this.texcoord = new Vector2(tcx, tcy);
            }

            public Vector3 position;
            public Vector3 normal;
            public Vector3 tangent;
            public Vector3 binormal;
            public Vector3 color;
            public Vector2 texcoord;

            public static VertexDeclaration Declaration
            {
                get
                {
                    return new VertexDeclaration(new VertexElement[]
                    {
                        new VertexElement(ElementBinding.Vertex   , ElementType.Float, 3, 68, 0),
                        new VertexElement(ElementBinding.Normal   , ElementType.Float, 3, 68, 12),
                        new VertexElement(ElementBinding.TexCoord2, ElementType.Float, 3, 68, 24),
                        new VertexElement(ElementBinding.TexCoord1, ElementType.Float, 3, 68, 36),
                        new VertexElement(ElementBinding.Color    , ElementType.Float, 3, 68, 48),
                        new VertexElement(ElementBinding.TexCoord0, ElementType.Float, 2, 68, 60),
                    });
                }
            }
        }

        #endregion

        #region Polygon Structure

        [StructLayout(LayoutKind.Sequential)]
        public struct Polygon
        {
            public Vertex A;
            public Vertex B;
            public Vertex C;
            public Polygon(Vertex A, Vertex B, Vertex C)
            {
                this.A = A;
                this.B = B;
                this.C = C;
            }

            public Plane Plane
            {
                get { return new Plane(A.position, B.position, C.position); }
            }

            public  bool Intersect(Ray ray)
            {
                Triangle triangle = new Triangle(this.A.position, this.B.position, this.C.position);

                return triangle.Intersect(ray);
            }

        }

        #endregion

        #region Face Structure

        [StructLayout(LayoutKind.Sequential)]
        public struct Face
        {
            public int  Subset;
            public uint A;
            public uint B;
            public uint C;
            public Face(int Subset, uint A, uint B, uint C)
            {
                this.Subset = Subset;
                this.A      = A;
                this.B      = B;
                this.C      = C;
            }
        }
       
        #endregion

        #region Fields

        private Device            device;
       
        private VertexBuffer      vertexBuffer;
       
        private List<IndexBuffer> indexBuffers;

        #endregion

        #region Constructors

        public  Mesh(Device device)
        {
            this.device          = device;
           
            this.vertexBuffer    = new VertexBuffer(Vertex.Declaration);
           
            this.indexBuffers    = new List<IndexBuffer>();
        }

        #endregion

        #region Properties

        public Device            Device      
        {
            get { return this.device; }
        }

        public VertexBuffer      VertexBuffer
        {
            get
            {
                return this.vertexBuffer;
            }
            set
            {
                this.vertexBuffer = value;
            }
        }

        public List<IndexBuffer> IndexBuffers
        {
            get
            {
                return this.indexBuffers;
            }
            set
            {
                this.indexBuffers = value;
            }
        }

        #endregion

        #region Draw

        /// <summary>
        /// Draws the entire mesh.
        /// </summary>
        public void Draw(Topology topology)
        {
            for (int i = 0; i < this.indexBuffers.Count; i++)
            {
                this.Draw(i, topology);
            }
        }

        /// <summary>
        /// Draws this mesh subset.
        /// </summary>
        /// <param name="subset"></param>
        public void Draw(int subset, Topology topology)
        {
             
            this.device.IndexBuffer       = this.indexBuffers[subset];
            this.device.VertexBuffer      = this.vertexBuffer;
            this.device.Draw(topology);
            this.device.IndexBuffer       = null;
            this.device.VertexBuffer      = null;
        }
     
  


        #endregion

        #region IDisposable Members

        private bool disposed = false;

        private void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                   
                }

                this.disposed = true;
            }
        }
        /// <summary>
        /// Disposes this IndexBuffer
        /// </summary>
        public void Dispose()
        {
            this.Dispose(true);

            GC.SuppressFinalize(this);
        }

        ~Mesh()
        {
            this.Dispose(false);
        }

        #endregion

       

        

     

    }
}
 